/* asmhead.nas */
/**
 * 妙啊！
 * binfo = (struct BOOTINFO *)0x0ff0;
 * 以0x0ff0作为结构体地址，对应asmhead.nas的cyls，也就是最开始的地址
 * 后面的每一个属性就可以直接对应地址了
 */
struct BOOTINFO
{
    char cyls;  /* 启动区读硬盘读到何处为止 */
    char leds;  /* 启动区键盘LED的状态 */
    char vmode; /* 显卡模式为多少位彩色 */
    char reserve;
    short scrnx, scrny; /* 画面分辨率 */
    char *vram;
};
#define ADR_BOOTINFO 0x00000ff0

/* naskfunc.nas */
void io_hlt(void);
void io_cli(void);
void io_sti(void);
void io_stihlt(void);
void io_out8(int port, int data);
int io_in8(int port);
int io_load_eflags(void);
void io_store_eflags(int eflags);
void load_gdtr(int limit, int addr);
void load_idtr(int limit, int addr);
void asm_inthandler21(void);
void asm_inthandler27(void);
void asm_inthandler2c(void);
int load_cr0(void);
void store_cr0(int cr0);

/* graphic.c */
void init_palette(void); /* 调色板 */
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen8(int *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font); /* 画字 */
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s);
void init_mouse_cursor8(char *mouse, char bc); /* 准备鼠标指针 */
void putblock8_8(char *vram, int vxsize, int pxsize, int pysize,
                 int px0, int py0, char *buf, int bxsize);
#define COL8_000000 0
#define COL8_FF0000 1
#define COL8_00FF00 2
#define COL8_FFFF00 3
#define COL8_0000FF 4
#define COL8_FF00FF 5
#define COL8_00FFFF 6
#define COL8_FFFFFF 7
#define COL8_C6C6C6 8
#define COL8_840000 9
#define COL8_008400 10
#define COL8_848400 11
#define COL8_000084 12
#define COL8_840084 13
#define COL8_008484 14
#define COL8_848484 15

/* dsctbl.c */
/* GDT global (segment) descriptor table 和 IDT interrupt descriptor table */
/* 全局段号记录表 和 中断记录表 */
/* 存放GDT的8字节的内容 */
/**
 * 段的信息
 * 8个字节
 * 段的大小
 * 段的起始地址
 * 段的管理属性（禁止写入，禁止执行，系统专用等）
 */
struct SEGMENT_DESCRIPTOR
{
    short limit_low, base_low;
    char base_mid, access_right;
    char limit_high, base_high;
};
/* 存放IDT的8字节的内容 */
struct GATE_DESCRIPTOR
{
    short offset_low, selector;
    char dw_count, access_right;
    short offset_high;
};
void init_gdtidt(void); /* 初始化GDT和IDT */
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
#define ADR_IDT 0x0026f800
#define LIMIT_IDT 0x000007ff
#define ADR_GDT 0x00270000
#define LIMIT_GDT 0x0000ffff
#define ADR_BOTPAK 0x00280000
#define LIMIT_BOTPAK 0x0007ffff
#define AR_DATA32_RW 0x4092
#define AR_CODE32_ER 0x409a
#define AR_INTGATE32 0x008e

/* int.c */
void init_pic(void);
/**
 * dsctbl.c -> init_gdtidt(void) -> set_gatedesc(idt + 0x21, (int)asm_inthandler21, 2 * 8, AR_INTGATE32)
 * -> asm_inthandler21(void) -> naskfunc.nas -> inthandler21(int *esp) -> int.c
 */
void inthandler21(int *esp);
void inthandler27(int *esp);
void inthandler2c(int *esp);
#define PIC0_ICW1 0x0020
#define PIC0_OCW2 0x0020
#define PIC0_IMR 0x0021
#define PIC0_ICW2 0x0021
#define PIC0_ICW3 0x0021
#define PIC0_ICW4 0x0021
#define PIC1_ICW1 0x00a0
#define PIC1_OCW2 0x00a0
#define PIC1_IMR 0x00a1
#define PIC1_ICW2 0x00a1
#define PIC1_ICW3 0x00a1
#define PIC1_ICW4 0x00a1

/* fifo.c */
/**
 * harib04e
 * 真 队列
 * 可变大小缓冲区，大小由程序指定
 * q：next_r队首
 * p：next_w队尾
 * size：当前缓冲区的总字节数
 * free：缓冲区里没有数据的字节数
 * flags：记录是否溢出
 */
struct FIFO8
{
    unsigned char *buf;
    int p, q, size, free, flags;
};
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf);
int fifo8_put(struct FIFO8 *fifo, unsigned char data);
int fifo8_get(struct FIFO8 *fifo);
int fifo8_status(struct FIFO8 *fifo);

/* keyboard.c */
#define PORT_KEYDAT 0x0060 /* 键盘端口 */
#define PORT_KEYCMD 0x0064
extern struct FIFO8 keyfifo;
void wait_KBC_sendready(void);
void init_keyboard(void);

/* mouse.c */
/**
 * DEC - decode
 * buf：记录数据
 * phase：记录接收鼠标数据的工作进展到的阶段
 * x, y：存放移动信息
 * btn：存放按键状态
 */
struct MOUSE_DEC
{
	unsigned char buf[3], phase;
	int x, y, btn;
};
extern struct FIFO8 mousefifo;
void enable_mouse(struct MOUSE_DEC *mdec);
int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat);

/* memory.c */
#define EFLAGS_AC_BIT 0x00040000
#define CR0_CACHE_DISABLE 0x60000000
#define MEMMAN_FREES 4090 /* 大约是32KB */
#define MEMMAN_ADDR 0x003c0000

struct FREEINFO
{ /* 可用信息 */
	unsigned int addr, size;
};

struct MEMMAN
{ /* 内存管理 */
	int frees, maxfrees, lostsize, losts;
	struct FREEINFO free[MEMMAN_FREES];
};

unsigned int memtest(unsigned int start, unsigned int end);
unsigned int memtest_sub(unsigned int start, unsigned int end);
void memman_init(struct MEMMAN *man);
unsigned int memman_total(struct MEMMAN *man);
unsigned int memman_alloc(struct MEMMAN *man, unsigned int size);
unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size);
int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size);

/* sheet.c */
/**
 * sheet：透明图层（作者没有找到合适的词）
 * buf：记录图层上所描画内容的地址 buffer
 * bxsize*bysize：图层的整体大小
 * vx0,vy0：图层在画面上的坐标，v代表VRAM
 * col_inv：透明色色号，color和invisible的组合略语
 * height：图层高度
 * flags：存放有关图层的各种设定信息
 */
struct SHEET
{
    unsigned char *buf;
    int bxsize, bysize, vx0, vy0, col_inv, height, flags;
};
#define MAX_SHEETS 256
/** 
 * SHTCTL：图层管理 sheet control
 * vram,xsize,ysize：代表VRAM的地址和画面的大小，省得每次从BOOTINFO取值
 * top：最上面图层的高度
 * sheets：记忆地址变量的领域，存的是图层的地址（由于sheets0中的图层顺序混乱，我们把他们按照高度升序排列，然后将其地址写入sheets中）
 * sheets0：存放256个图层的信息
 */
struct SHTCTL
{
    unsigned char *vram;
    int xsize, ysize, top;
    struct SHEET *sheets[MAX_SHEETS];
    struct SHEET sheets0[MAX_SHEETS];
};
struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize);
struct SHEET *sheet_alloc(struct SHTCTL *ctl);
void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv);
void sheet_updown(struct SHTCTL *ctl, struct SHEET *sht, int height);
void sheet_refresh(struct SHTCTL *ctl, struct SHEET *sht, int hx0, int hy0, int bx1, int by1);
void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1);
void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0);
void sheet_free(struct SHTCTL *ctl, struct SHEET *sht);
